//
// Created on 24/7/31.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#include "CertificateEnvironment.h"

#define LOG_DOMAIN  0x0
#define LOG_TAG     "CertificateEnvironment"
#include <hilog/log.h>
#include <filesystem>
#include <fstream>

#include "AbilityContext.h"
#include "mkcert.h"


namespace {
void logFileContent(const std::filesystem::path &path) {
    std::ifstream inf(path);
    for (std::array<char, 4096> l; inf.getline(l.data(), 4096);) {
        OH_LOG_DEBUG(LOG_APP, "%{public}s content |%{public}s", path.c_str(), l.data());
    }
}
}

void CertificateEnvironment::load(bool force_renew) {
    std::unique_lock l(_mtx);
    /* initialize cert path if not already */
    if (!_cert_dir) {
        // TODO programmatically acquire filesystem path
        _cert_dir = AbilityContext::DISTRIBUTED_DIR / "cert";
    }
    /* if cert already exists, do nothing */
    if (!force_renew) {
        if (std::filesystem::exists(*_cert_dir)) {
            OH_LOG_INFO(LOG_APP, "Certificate already exists under %{public}s", _cert_dir->c_str());
            logFileContent(*_cert_dir / CERT_FILENAME);
            logFileContent(*_cert_dir / P12_FILENAME);
            logFileContent(*_cert_dir / KEY_PAIR_FILENAME);
            return;
        }
    }
    /* if not, clear cert workspace */
    OH_LOG_INFO(LOG_APP, "Removing old certificate under %{public}s if any", _cert_dir->c_str());
    std::filesystem::remove_all(*_cert_dir);
    std::filesystem::create_directory(*_cert_dir);
    /* generate if not already exists */
    OH_LOG_INFO(LOG_APP, "Generating certificate under %{public}s", _cert_dir->c_str());
    const auto cert_path = *_cert_dir / CERT_FILENAME;
    const auto p12_path = *_cert_dir / P12_FILENAME;
    const auto keypair_path = *_cert_dir / KEY_PAIR_FILENAME;
    const auto cert = mkcert_generate();
    mkcert_save(cert_path.c_str(), p12_path.c_str(), keypair_path.c_str(), cert);
    mkcert_free(cert);
}

std::filesystem::path CertificateEnvironment::get_cert_path() {
    std::unique_lock l(_mtx);
    if (!_cert_dir) {
        load();
    }
    return *_cert_dir / CERT_FILENAME;
}

std::filesystem::path CertificateEnvironment::get_p12_path() {
    std::unique_lock l(_mtx);
    if (!_cert_dir) {
        load();
    }
    return *_cert_dir / P12_FILENAME;
}

std::filesystem::path CertificateEnvironment::get_keypair_path() {
    std::unique_lock l(_mtx);
    if (!_cert_dir) {
        load();
    }
    return *_cert_dir / KEY_PAIR_FILENAME;
}
    